#include "cioMst.h"
#include <string.h>

using namespace std;

void cioMst::RxData(const vector<uint8_t>& rx, queue<MstCioObj> &extTaskQueue)
{
    /* 全部读取到FIFO中 */
    m_stat->rxBytes += rx.size();
    if (m_rxBuffer.capacity() > BUFFER_MAX_SIZE) {
        return;
    }
    m_rxBuffer.insert(m_rxBuffer.end(), rx.begin(), rx.end());
    if (m_rxBuffer.size() <= m_pkgHead.size()) {
        return;
    }
    size_t procedFifoLen = 0;
    /* 查找所有包头位置 */
    queue<size_t> headQueue;
    for (size_t idx = 0; idx < m_rxBuffer.size() - m_pkgHead.size(); idx++) {
        int ret = memcmp(m_pkgHead.data(), m_rxBuffer.data() + idx, m_pkgHead.size());
        if (ret == 0) {
            m_stat->rxPkg++;
            headQueue.push(idx);
        }
    }
    /* 将接收缓存切片，逐一填到待处理帧中 */
    while (!headQueue.empty()) {
        size_t currPos = headQueue.front();
        headQueue.pop();
        const uint8_t* data = m_rxBuffer.data() + currPos;
        size_t dataLen = (headQueue.empty() ? m_rxBuffer.size() : headQueue.front()) - currPos;
        procedFifoLen += dataLen;
        size_t validLen =  min(dataLen, DecodePkgLen(data, dataLen));
        MstCioObj event = Decode(data, validLen);
        if (event.data.empty()) {
            continue;
        }
        m_stat->rxValidBytes += validLen;
        extTaskQueue.push(event);
    }
    /* export FIFO */
    m_rxBuffer.erase(m_rxBuffer.begin(), m_rxBuffer.begin() + procedFifoLen);
    if (m_rxBuffer.capacity() > 1024 * 10) {
        m_rxBuffer.clear();
    }
    return;
}

FrmTransState cioMst::CheckOutRx(const uint8_t* rxData, size_t dataLen) const
{
    if (rxData == nullptr || dataLen < sizeof(pkg)) {
        return FRM_LENERR;
    }
    const pkg* o = reinterpret_cast<const pkg*>(rxData);
    /* 校验帧头 */
    if (memcmp(o->head, m_pkgHead.data(), m_pkgHead.size()) != 0) {
        return FRM_HEADERR;
    }
    /* 校验RCC */
    const uint8_t* dataAddr = rxData + PKG_DATA_OFFSET;
    uint32_t rccRcv = *((uint32_t*)(dataAddr + o->dataLen));
    uint32_t rcc = 0;
    for (const uint8_t* pData = rxData; pData != dataAddr + o->dataLen; pData++) {
        rcc += *pData;
    }
    if (rcc != rccRcv) {
        return FRM_RCCERR;
    }

    return  FRM_OK;
}

MstCioObj cioMst::Decode(const uint8_t* data, size_t dataLen) const
{
    MstCioObj task;
    /* 长度校验 */
    FrmTransState ret = CheckOutRx(data, dataLen);
    if (ret != FRM_OK) {
        return task;
    }
    /* 数据拷贝 */
    const pkg* o = reinterpret_cast<const pkg*>(data);
    task.type = o->type;
    const uint8_t* dataAddr = data + PKG_DATA_OFFSET;
    task.data.assign(dataAddr, dataAddr + o->dataLen);
    return task;
}

size_t cioMst::DecodePkgLen(const uint8_t* rxData, size_t dataLen) const
{
    if (rxData == nullptr || dataLen < sizeof(pkg)) {
        return 0;
    }
    const pkg* o = reinterpret_cast<const pkg*>(rxData);
    return o->dataLen + PKG_DATA_OFFSET + sizeof(o->rcc);
}

void cioMst::TxPkg(vector<uint8_t>& dst, pkgType type, const void* data, size_t len)
{
    uint8_t reserved[4] = {0};
    if (data == nullptr || len == 0) {
        data = reserved;
        len = sizeof(reserved); // 至少填充4个字节
    }
    pkg o;
    uint8_t* pkgAddr = reinterpret_cast<uint8_t*>(&o);
    const uint8_t* dataAddr = reinterpret_cast<const uint8_t*>(data);
    memset(pkgAddr, 0, sizeof(pkg));
    o.type = type;
    o.dataLen = static_cast<uint32_t>(len);
    memcpy(o.head, m_pkgHead.data(), m_pkgHead.size());
    for (const uint8_t* pRcc = pkgAddr; pRcc != pkgAddr + PKG_DATA_OFFSET; pRcc++) {
        o.rcc += *pRcc;
    }
    for (size_t idx = 0; idx < len; idx++) {
        o.rcc += dataAddr[idx];
    }
    uint8_t* rccAddr = reinterpret_cast<uint8_t*>(&o.rcc);
    /* makeup data stream */
    dst.insert(dst.end(), pkgAddr, pkgAddr + PKG_DATA_OFFSET);
    dst.insert(dst.end(), dataAddr, dataAddr + len);
    dst.insert(dst.end(), rccAddr, rccAddr + sizeof(o.rcc));
}

MstStatisticsHandle cioMst::GetStatic()
{
    m_stat->currBufferSize = m_rxBuffer.size();
    return m_stat;
}
